package de.stefanocke.roo.wicket.templates

import de.stefanocke.roo.wicket.ApplicationService
import de.stefanocke.roo.wicket.RooStereotype
import de.stefanocke.roo.xtend.ImportResolverExtensions
import java.io.File
import org.springframework.roo.model.ImportRegistrationResolverImpl
import org.springframework.roo.model.JavaPackage
import org.springframework.roo.model.JavaType
import org.springframework.roo.project.Path
import org.springframework.roo.project.LogicalPath
import org.springframework.roo.classpath.PhysicalTypeIdentifier
import static extension de.stefanocke.roo.xtend.RooExtensions.*
/**
 * Template to create a Java class and optionally the according html
 */
class JavaHtmlTemplate extends ImportResolverExtensions implements IJavaTemplate {
	
	extension TemplateSupportService templateSupport
	extension Templates templates
	ApplicationService appService
	JavaType type
	String module
	boolean exists
	
	override init(Templates templates){
		this.templates = templates
		this.templateSupport = templates.templateSupportService
		this.appService = templates.applicationService
		val cid = appService.findClassOrInterfaceDetailsWithStereotype(templates.focusedModule,stereotype)
		this.type = cid?.name
		if(this.type != null){
			module = PhysicalTypeIdentifier::getPath(cid.declaredByMetadataId).module
			//TODO: Determine the module of the found type
			//module == moduleForType()
			this.exists = true
			init(new ImportRegistrationResolverImpl(^package))	
		} else {
			module = templates.focusedModule
		}
		//this
	}
	
	def templates(){
		templates
	}
	
	//Get the java class from another template. Use short form when in same package.
	def generatedJavaType(Class templateClass){
		templateClass.template.getJavaType
	}
	
	def getPackage(){
		javaType.^package
	}
	override getJavaType(){
		createJavaTypeIfNull()
		type
	}
	override exists(){
		exists
	}
	def createJavaTypeIfNull(){
		if (type==null) {
			val pckg = packageToUseWhenNew
			type = new JavaType(pckg.fqnAppend(javaClassNameWhenNew))			
			init(new ImportRegistrationResolverImpl(pckg))		
		}
	}
	
	def JavaPackage packageToUseWhenNew(){
		
			//At first, we look if some other classes already exist that should go into same subpackage.
			//If so, we ignore everything else and create the new type in the same existing pacakges.
			//If not, then the default web package / domain package is used and the suppackage name is appended.
			val candidates = templates.templates.filter(t | 
				t.exists && 
				t.subPackageToUseWhenNew == subPackageToUseWhenNew &&
				t.domain == domain
			)
			if(!candidates.empty)
				candidates.iterator.next.javaType.^package //return the package of first candidate
			else {
				val base = 
					if (domain) 
						templates.domainPackage 
					else 
						templates.webPackage
				if(subPackageToUseWhenNew==null) 
					base
				else
					new JavaPackage(base.fqnAppend(subPackageToUseWhenNew))	
			} 
	}
	
	def simpleTypeName(){
		javaType.simpleTypeName
	}
	/**
	 * The name of the class if it does not yet exist and must be freshly created.
	 */
	def String javaClassNameWhenNew(){
	}
	def String stereotype() {
	}
	
	def replaceDot(JavaType javaType){
		javaType.fullyQualifiedTypeName.replace('.'.charAt(0), File::separatorChar)
	}
	def javaPath(){
		javaType.replaceDot + ".java";
	}
	def htmlPath(){
		javaType.replaceDot + ".html";
	}
		
	override createFiles(boolean forceUpdate) {
		if(!exists || forceUpdate){
			LogicalPath::getInstance(Path::SRC_MAIN_JAVA, module).createFile(javaPath, buildJava)
			LogicalPath::getInstance(Path::SRC_MAIN_RESOURCES, module).createFile(htmlPath, buildHtml)
		}
	}

	//the name of the subpackage (below "web" or "domain" package) to use when the Java class does not yet exist
	//and is freshly created
	override subPackageToUseWhenNew(){
		null
	}
	//By default, a Template generates a Wicket artifact. If you want a template to generate something in
	//the domain package, override that method to return true
	override isDomain(){
		false
	}
	
	def buildJava(){
		createJavaTypeIfNull()  //make sure, an ImportRegistrationResolver is initialized
		val contents = buildJavaContents()
		'''
		package «^package»;
		
		«FOR imp : importRegistrationResolver.registeredImports.sort»
		import «imp.fullyQualifiedTypeName»;
		«ENDFOR»
		
		«contents»
		'''	
	}
	
	def stereotypeAnnotation(){
		stereotypeAnnotation(stereotype)
	}
	def stereotypeAnnotation(String stereotype){
		'''@«typeof(RooStereotype).name.resolve»("«stereotype»")'''
	}
	def CharSequence buildJavaContents(){
		
	}
	
	//wraps the interesting content in some html body and/or head
	def buildHtml(){
		val head = buildHtmlHead
		val body = buildHtmlBody
		if(body!=null){
			'''
			<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
			"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
			<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.sourceforge.net/">
			«IF head != null»
				<head>
					«head»
				</head>
			«ENDIF»
			    <body>
			    	«buildHtmlBody»
			    </body>
			</html>
			'''	
		}
	}
	
	def CharSequence buildHtmlHead(){}
	def CharSequence buildHtmlBody(){}
	
	
	
}